#ifndef DATABASE_H_
#define DATABASE_H_

#include <wx/wx.h>
#include <wx/wxsqlite3.h>
#include "../../Main.h"
#include "DBModule.h"
#include "DBType.h"
#include "../Buddy.h"
#include "../Group.h"
#include <vector>
#include "HistoryEntry.h"
#include "HistorySession.h"
#include "../Status.h"
#include "../Account.h"

namespace Impp{

class DBModule;

class Database
{

private:
	wxSQLite3Database db;
	std::vector<SelfBuddy*> selfs;
	std::vector<Group*> groups;
	std::vector<Buddy*> buddies;
	Group* notInListGroup;

	friend class DBModule;
	friend class HistorySession;

public:
	Database(const wxString & profilFile);
	virtual ~Database();

	DBModule createModule(const wxString  & name);
	DBModule getModule(const wxString  & name);

	Group* createGroup(const wxString & name,const int & flags = GROUP_NOFLAG);
	Buddy* createBuddy(const db_id & accountId, const wxString & screenName, const wxString & custonName, Group* subGroup, const int & flags);
	Group* getRootGroup();
	Group* getNotInListGroup(std::vector<Group*> & groups);

	void getAccounts(std::vector<Account*> & accounts);
	Account* createAccount(const int flags, const wxString & classname, const wxString & screenname, const wxString & password);
	void updateAccount(Account* account);
	void deleteAccount(const db_id & id);

	void getGroupsWithBuddies(std::vector<Group*> & groups, std::vector<Buddy*> & buddies);

	void updateBuddyCustomName(Buddy* buddy, const wxString & customName);
	void updateBuddyScreenName(Buddy* buddy, const wxString & screenName);
	void updateBuddyFlags(Buddy* buddy,const int & flags);
	void updateGroup(Buddy* buddy, Group* newGroup);

	void updateGroupFlags(Group* group,const int & flags);

	StatusAndMsg* createStatusMessage(db_id accountId, const Status & status,const wxString & title, const wxString & msg, int flags);
	void updateStatusMessage(StatusAndMsg* statusMsg);
	void deleteStatusMessage(StatusAndMsg* statusMsg);
	void getStatusMessages(std::vector<StatusAndMsg*>& out, db_id accountId);

	db_id saveInHistory(const wxDateTime & time, Buddy* buddy, const wxString & msg, bool out);
	//void getHistoryEntriesBetween(std::vector<HistoryEntry*> & out, Buddy* buddy,const wxDateTime & after,const wxDateTime & before);

	wxString getStringValue(Buddy* buddy,const wxString & name,const wxString  & std);
	db_int	getIntValue(Buddy* buddy,const wxString & name,const db_int & std);
	db_float getFloatValue(Buddy* buddy,const wxString & name,const db_float & std);

	void setStringValue(Buddy* buddy,const wxString & name,const wxString  & value);
	void setIntValue(Buddy* buddy,const wxString & name,const db_int & value);
	void setFloatValue(Buddy* buddy,const wxString & name,const db_float & value);

	wxString getStringValue(Group* group,const wxString & name,const wxString  & std);
	db_int	getIntValue(Group* group,const wxString & name,const db_int & std);
	db_float getFloatValue(Group* group,const wxString & name,const db_float & std);

	void setStringValue(Group* group,const wxString & name,const wxString  & value);
	void setIntValue(Group* group,const wxString & name,const db_int & value);
	void setFloatValue(Group* group,const wxString & name,const db_float & value);

	HistorySession* getCurrentHistorySession(Buddy* buddy);
	void getHistoryYears(std::vector<int>& out, Buddy* buddy);
	void getHistoryMonths(std::vector<int>& out, Buddy* buddy, int year);
	void getHistorySessions(std::vector<HistorySession*>& out, Buddy* buddy, int year, int month);

	bool doesHistoryEntryExist(Buddy* buddy, bool out, wxDateTime time, const wxString& msg);
	void recreateHistorySessions(Buddy* buddy);

	void getHistoryEntries(std::vector<HistoryEntry*> & out, Buddy* buddy, const wxDateTime & since);
	db_id saveInHistoryInSession(const wxDateTime & time, Buddy* buddy, const wxString & msg, bool out, const db_id & sessionId);

private:
	wxString getStringValue(const db_id & moduleId,const wxString & name,const wxString  & std);
	db_int	getIntValue(const db_id & moduleId,const wxString & name,const db_int & std);
	db_float getFloatValue(const db_id & moduleId,const wxString & name,const db_float & std);

	void setStringValue(const db_id & moduleId,const wxString & name,const wxString  & value);
	void setIntValue(const db_id & moduleId,const wxString & name,const db_int & value);
	void setFloatValue(const db_id & moduleId,const wxString & name,const db_float & value);

private:
	void open(const wxString & profilFile);
	void close();
	void createBuddyTable();
	void createGroupTable();
	void createModuleTable();
	void createValueTables();
	void createHistoryTable();
	void createStatusMessageTable();
	void createAccountsTable();
	void checkDatabaseTables();

	bool checkTableFiledExsists(const wxString & table, const wxString & field);
	void createTableField(const wxString & table, const wxString & field, const wxString & type, const wxString & defaultValue);
	bool checkAndCreate(const wxString & table, const wxString & field, const wxString & type, const wxString & defaultValue);

	Group* getGroup(db_id id);
	Buddy* getBuddy(db_id id);
	wxString buddyToModuleString(Buddy* b);
	wxString groupToModuleString(Group* g);
	HistorySession* createHistorySession(Buddy* buddy, const wxDateTime & sessionStart);
	HistorySession* getLastHistorySession(Buddy* buddy);
	void getHistoryEntries(std::vector<HistoryEntry*> & out, HistorySession* session);
	HistoryEntry* getLastHistoryEntry(HistorySession* session);

	Buddy* loadBuddyObject(const db_id & id, const db_id & accountId, const wxString & screenName, const wxString & custonName, Group* subGroup, const int & flags);
};

}

#endif /*DATABASE_H_*/
